package base.Controller;

import base.Model.ImagePreviewPane;
import base.Model.SelectionRectangle;
import javafx.fxml.FXML;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.*;
import javafx.scene.image.ImageView;
import javafx.scene.layout.*;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.MouseButton;
import javafx.geometry.Bounds;
import java.io.File;
import java.util.List;
import java.util.stream.Collectors;
import java.io.IOException;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.input.Clipboard;
import javafx.scene.Node;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;

public class MainController {
    @FXML private TreeView<File> directoryTree;
    @FXML private FlowPane imagePreviewPane;
    @FXML private Label currentDirectoryLabel;
    @FXML private Label statusLabel;
    @FXML private Button slideshowButton;
    @FXML private HBox btm;
    @FXML private ImageView icon;

    private final String[] SUPPORTED_EXTENSIONS = {
            ".jpg", ".jpeg", ".gif", ".png", ".bmp"
    };

    private double dragStartX, dragStartY;
    private SelectionRectangle selectionRect;


    private TreeItem<File> castToFileTreeItem(TreeItem<?> item) {
        if (item != null && item.getValue() instanceof File) {
            return (TreeItem<File>) item;
        }
        return null;
    }



    @FXML
    public void initialize() {
        //控制文件名的显示
        directoryTree.setCellFactory(tv -> new TreeCell<>() {
            @Override
            protected void updateItem(File item, boolean empty) {
                super.updateItem(item, empty);
                if (empty || item == null) {
                    setText(null);
                    setGraphic(null);
                } else {
                    // 判断是否为根节点
                    if ("此电脑".equals(item.getName())) {
                        setText("此电脑"); // 根节点显示为 "此电脑"
                    } else if (item.isDirectory() && item.getParent() == null) {
                        // 磁盘根目录（如 C:、D:）
                        setText(item.getAbsolutePath()); // 显示完整路径
                    } else {
                        // 普通文件或目录
                        setText(item.getName());
                    }
                    
                    // 设置图标
                    TreeItem<File> treeItem = getTreeItem();
                    if (treeItem != null) {
                        // 为所有节点设置图标，包括叶子节点
                        javafx.scene.image.Image folderIcon = new javafx.scene.image.Image(
                            getClass().getResourceAsStream("/image/img_1.png"));
                        ImageView imageView = new ImageView(folderIcon);
                        imageView.setFitHeight(16);
                        imageView.setFitWidth(16);
                        setGraphic(imageView);
                    }
                }
            }
        });

        // 初始化目录树
        setupDirectoryTree();

        // 设置目录树选择监听器
        directoryTree.getSelectionModel().selectedItemProperty().addListener(
                (observable, oldValue, newValue) -> {
                    if (newValue != null) {
                        loadImagesFromDirectory(newValue.getValue());
                    }
                }
        );

        // 修改展开事件监听器的注册方式
        directoryTree.addEventHandler(TreeItem.treeNotificationEvent(), event -> {
            if (event.getEventType() == TreeItem.branchExpandedEvent()) {
                TreeItem<File> item = castToFileTreeItem(event.getTreeItem());
                if (item != null) {
                    System.out.println("节点展开: " + item.getValue());
                    loadDirectory(item);
                }
            }
        });

        // 递归为所有子节点添加展开事件监听器
        addExpandListenerToChildren(directoryTree.getRoot());


        btm.setPadding(new Insets(0,10,0,10));
        // 设置幻灯片按钮事件
        slideshowButton.setOnAction(e -> openSlideshow());

        // 添加多选框拖拽功能
        setupMultiSelect();

        // 设置右键菜单
        setupContextMenu();
        
        // 将控制器实例存储在窗口属性中
        Platform.runLater(() -> {
            if (imagePreviewPane.getScene() != null && imagePreviewPane.getScene().getWindow() != null) {
                imagePreviewPane.getScene().getWindow().getProperties().put("controller", this);
            }
        });
    }

    // 新增方法：递归为所有子节点添加展开事件监听器
    private void addExpandListenerToChildren(TreeItem<File> node) {
        for (TreeItem<File> child : node.getChildren()) {
            child.addEventHandler(TreeItem.branchExpandedEvent(), event -> {
                System.out.println("子节点展开事件触发: " + ( castToFileTreeItem(event.getSource())).getValue().getPath());
                TreeItem<File> source =  castToFileTreeItem(event.getSource());
                loadDirectory(source);
            });
            addExpandListenerToChildren(child);
        }
    }

    private void loadDirectory(TreeItem<File> node) {
        File file = node.getValue();

        // 如果是空的占位节点，直接返回
        if (!file.exists()) {
            return;
        }

        System.out.println("正在加载目录: " + file.getAbsolutePath());

        // 清空现有子节点（可能包含占位节点）
        node.getChildren().clear();

        File[] files = file.listFiles(File::isDirectory);

        if (files != null) {
            for (File childFile : files) {


                TreeItem<File> childNode = new TreeItem<>(childFile);

                node.getChildren().add(childNode);

                // 检查子目录是否有更深层次的目录
                File[] subDirs = childFile.listFiles(File::isDirectory);

                if (subDirs != null && subDirs.length > 0) {
                    // 添加一个占位子节点，表示此目录下还有子目录
                    childNode.getChildren().add(new TreeItem<>(new File("")));

                    // 为新创建的节点添加展开事件监听器
                    //性能提升，懒加载
                    childNode.addEventHandler(TreeItem.branchExpandedEvent(), event -> {
                        System.out.println("新节点展开事件触发: " + ( castToFileTreeItem(event.getSource())).getValue().getPath());
                        TreeItem<File> src =  castToFileTreeItem(event.getSource());
                        loadDirectory(src);
                    });
                }

            }
        }
    }

    private void setupDirectoryTree() {
        // 获取根目录
        File[] roots = File.listRoots();
        //根节点
        TreeItem<File> rootItem = new TreeItem<>(new File("此电脑"));

        for (File root : roots) {
            TreeItem<File> rootNode = new TreeItem<>(root);
            rootItem.getChildren().add(rootNode);
            loadDirectory(rootNode);
        }

        directoryTree.setRoot(rootItem);


    }

    private void loadImagesFromDirectory(File directory) {
        ((Pane)imagePreviewPane).getChildren().clear();

        if (directory == null || !directory.isDirectory()) {
            return;
        }

        File[] imageFiles = directory.listFiles(this::isImageFile);
        if (imageFiles == null) {
            return;
        }

        // 更新目录标签
        currentDirectoryLabel.setText(directory.getName() + " (" + imageFiles.length + "张图片)");
        icon.setVisible(true);
        // 计算总大小
        long totalSize = 0;
        for (File file : imageFiles) {
            totalSize += file.length();
        }

        // 更新状态标签
        statusLabel.setText(String.format("共%d张图片，总大小：%.2fMB",
                imageFiles.length, totalSize / (1024.0 * 1024.0)));
//        statusLabel.setPadding(new Insets(0,0,0,10));
        // 分批加载图片预览
        //创建task实例用于执行后台任务
        Task<Void> loadTask = new Task<>() {
            @Override
            protected Void call() {
                int batchSize = 20; // 每批加载的图片数量
                for (int i = 0; i < imageFiles.length; i += batchSize) {
                    final int start = i;
                    final int end = Math.min(i + batchSize, imageFiles.length);

                    //UI 更新操作在 JavaFX 应用程序线程上执行
                    Platform.runLater(() -> {
                        for (int j = start; j < end; j++) {
                            ImagePreviewPane preview = new ImagePreviewPane(imageFiles[j]);
                            ((Pane)imagePreviewPane).getChildren().add(preview);
                        }
                    });

                    try {
                        Thread.sleep(100); // 批次间短暂暂停，避免UI卡顿
                    } catch (InterruptedException e) {
                        break;
                    }
                }
                return null;
            }
        };
        //创建一个新线程来执行任务
        Thread thread = new Thread(loadTask);
        //设置为守护线程
        thread.setDaemon(true);
        thread.start();
    }

    // 添加更新选中计数的方法
    public void updateSelectedCountLabel(long selectedCount, long totalCount) {
        if (selectedCount > 0) {
            // 如果有选中的图片，显示选中计数
            currentDirectoryLabel.setText(directoryTree.getSelectionModel().getSelectedItem().getValue().getName() + " (已选中 " + selectedCount + "/" + totalCount + " 张图片)");
        } else {
            // 如果没有选中的图片，显示总计数
            currentDirectoryLabel.setText(directoryTree.getSelectionModel().getSelectedItem().getValue().getName() + " (" + totalCount + "张图片)");
        }
    }

    private boolean isImageFile(File file) {
        if (!file.isFile()) {
            return false;
        }
        String name = file.getName().toLowerCase();
        for (String ext : SUPPORTED_EXTENSIONS) {
            if (name.endsWith(ext)) {
                return true;
            }
        }
        return false;
    }

    private void openSlideshow() {
        try {
            // 获取当前目录下的所有图片文件
            //通过流式处理其子节点
            List<File> imageFiles = ((Pane)imagePreviewPane).getChildren().stream()
                    .filter(node -> node instanceof ImagePreviewPane)
                    .map(node -> ((ImagePreviewPane) node).getImageFile())
                    .collect(Collectors.toList());

            // 获取选中的图片索引
            int startIndex = 0;
            List<ImagePreviewPane> selectedImages = getSelectedImages();
            if (!selectedImages.isEmpty()) {
                startIndex = imageFiles.indexOf(selectedImages.get(0).getImageFile());
            }

            // 加载幻灯片播放窗口
            FXMLLoader loader = new FXMLLoader(getClass().getResource("/FXML/slideshow-view.fxml"));
            Parent root = loader.load();

            // 配置幻灯片控制器
            SlideshowController controller = loader.getController();
            controller.setImageFiles(imageFiles, startIndex);

            // 创建新窗口
            Stage stage = new Stage();
            stage.setTitle("幻灯片播放");
            stage.setScene(new Scene(root));
            stage.show();

        } catch (IOException e) {
            showError("打开幻灯片播放失败", e.getMessage());
        }
    }

    private void showError(String title, String message) {
        Alert alert = new Alert(Alert.AlertType.ERROR);
        alert.setTitle(title);
        alert.setHeaderText(null);
        alert.setContentText(message);
        alert.showAndWait();
    }

    private void setupMultiSelect() {
        selectionRect = new SelectionRectangle();
        ((Pane)imagePreviewPane).getChildren().add(selectionRect);
        selectionRect.setVisible(false);

        // 不在这里设置鼠标事件，而是在setupMouseEvents方法中统一处理
    }

    // 设置右键菜单
    private void setupContextMenu() { 
        ContextMenu contextMenu = new ContextMenu(); 
        // 设置上下文菜单的整体背景颜色 
        contextMenu.setStyle("-fx-background-color: rgb(48, 49, 48);"); 
        
        MenuItem pasteItem = new MenuItem("粘贴图片"); 
        // 设置菜单项的背景颜色、文字颜色以及选中时的颜色
        pasteItem.setStyle("-fx-background-color: rgb(48, 49, 48); -fx-text-fill: white;" +
                       "-fx-background: rgb(48, 49, 48) when hover;" +
                       "-fx-background: rgb(48, 49, 48) when pressed;" +
                       "-fx-background: rgb(48, 49, 48) when selected;"); 
        
        pasteItem.setOnAction(e -> pasteImages());

        contextMenu.getItems().add(pasteItem);

        // 为图片预览区域添加上下文菜单
        imagePreviewPane.setOnContextMenuRequested(e -> {
            // 检查点击位置是否在空白区域
            Node clickedNode = e.getPickResult().getIntersectedNode();
            boolean isBlankArea = true;

            // 检查是否点击在图片预览上
            if (clickedNode instanceof ImagePreviewPane ||
                (clickedNode.getParent() != null && clickedNode.getParent() instanceof ImagePreviewPane)) {
                isBlankArea = false;
            }

            // 如果是空白区域，显示上下文菜单
            if (isBlankArea && !(clickedNode instanceof SelectionRectangle)) {
                contextMenu.show(imagePreviewPane, e.getScreenX(), e.getScreenY());
            }
        });

        // 添加窗口失去焦点事件，用于隐藏菜单
        imagePreviewPane.sceneProperty().addListener((observable, oldScene, newScene) -> {
            if (newScene != null) {
                newScene.windowProperty().addListener((observableWindow, oldWindow, newWindow) -> {
                    if (newWindow != null) {
                        newWindow.focusedProperty().addListener((observableFocus, oldFocus, newFocus) -> {
                            if (!newFocus && contextMenu.isShowing()) {
                                contextMenu.hide();
                            }
                        });
                    }
                });
            }
        });

        // 设置统一的鼠标事件处理
        setupMouseEvents(contextMenu);
    }

    // 新增方法：统一处理鼠标事件
    private void setupMouseEvents(ContextMenu contextMenu) {
        imagePreviewPane.setOnMousePressed((MouseEvent e) -> {
            if (e.getButton() == MouseButton.PRIMARY) {
                // 处理右键菜单隐藏
                if (contextMenu.isShowing()) {
                    contextMenu.hide();
                    // 如果只是为了隐藏菜单而点击，不要触发选择框
                    return;
                }

                // 处理多选框
                dragStartX = e.getX();
                dragStartY = e.getY();
                selectionRect.setX(dragStartX);
                selectionRect.setY(dragStartY);
                selectionRect.setWidth(0);
                selectionRect.setHeight(0);
                selectionRect.setVisible(true);

                // 检查点击位置是否在空白区域
                Node clickedNode = e.getPickResult().getIntersectedNode();
                boolean isBlankArea = true;

                // 检查是否点击在图片预览上
                if (clickedNode instanceof ImagePreviewPane ||
                    (clickedNode.getParent() != null && clickedNode.getParent() instanceof ImagePreviewPane)) {
                    isBlankArea = false;
                }

                // 如果点击在空白区域，且没有按住Ctrl键，取消所有选择
                if (isBlankArea && !(clickedNode instanceof SelectionRectangle) && !e.isControlDown()) {
                    clearAllSelections();
                }
            }
        });

        imagePreviewPane.setOnMouseDragged((MouseEvent e) -> {
            if (e.getButton() == MouseButton.PRIMARY && selectionRect.isVisible()) {
                double currentX = e.getX();
                double currentY = e.getY();

                // 更新选择框
                selectionRect.updateSize(
                        Math.min(dragStartX, currentX),
                        Math.min(dragStartY, currentY),
                        Math.abs(currentX - dragStartX),
                        Math.abs(currentY - dragStartY)
                );

                // 选择框内的图片
                selectImagesInRect(selectionRect.getBoundsInParent());
            }
        });

        imagePreviewPane.setOnMouseReleased((MouseEvent e) -> {
            if (e.getButton() == MouseButton.PRIMARY) {
                selectionRect.setVisible(false);
            }
        });
    }

    private void clearAllSelections() {
        ((Pane)imagePreviewPane).getChildren().stream()
                .filter(node -> node instanceof ImagePreviewPane)
                .map(node -> (ImagePreviewPane) node)
                .forEach(preview -> preview.setSelected(false));
    }

    private void selectImagesInRect(Bounds rectBounds) {
        ((Pane)imagePreviewPane).getChildren().stream()
                .filter(node -> node instanceof ImagePreviewPane)
                .map(node -> (ImagePreviewPane) node)
                .forEach(preview -> {
                    if (preview.getBoundsInParent().intersects(rectBounds)) {
                        preview.setSelected(true);
                    }
                });
    }

    // 获取当前选中的图片
    private List<ImagePreviewPane> getSelectedImages() {
        return ((Pane)imagePreviewPane).getChildren().stream()
                .filter(node -> node instanceof ImagePreviewPane)
                .map(node -> (ImagePreviewPane) node)
                .filter(ImagePreviewPane::isSelected)
                .collect(Collectors.toList());
    }

    // 粘贴图片方法
    private void pasteImages() {
        Clipboard clipboard = Clipboard.getSystemClipboard();

        // 检查剪贴板中是否有图片
        if (clipboard.hasFiles()) {
            // 从剪贴板获取文件
            List<File> files = clipboard.getFiles();

            // 获取当前选中的目录
            TreeItem<File> selectedItem = directoryTree.getSelectionModel().getSelectedItem();
            if (selectedItem == null || selectedItem.getValue() == null) {
                showError("错误", "请先选择一个目录");
                return;
            }

            File targetDir = selectedItem.getValue();
            if (!targetDir.isDirectory()) {
                showError("错误", "选择的不是有效目录");
                return;
            }

            // 复制文件到目标目录
            int successCount = 0;
            for (File file : files) {
                if (isImageFile(file)) {
                    try {
                        // 创建目标文件
                        File targetFile = new File(targetDir, file.getName());

                        // 如果文件已存在，创建一个新名称
                        if (targetFile.exists()) {
                            String newName = generateNewFileName(targetDir, file.getName());
                            targetFile = new File(targetDir, newName);
                        }

                        // 复制文件
                        java.nio.file.Files.copy(file.toPath(), targetFile.toPath());
                        successCount++;
                    } catch (IOException ex) {
                        showError("粘贴失败", "无法粘贴文件: " + file.getName() + "\n" + ex.getMessage());
                    }
                }
            }

            // 刷新当前目录
            if (successCount > 0) {
                loadImagesFromDirectory(targetDir);
                showMessage("成功粘贴 " + successCount + " 个图片文件");
            }
        } else if (clipboard.hasImage()) {
            // 从剪贴板获取图片
            javafx.scene.image.Image image = clipboard.getImage();

            // 获取当前选中的目录
            TreeItem<File> selectedItem = directoryTree.getSelectionModel().getSelectedItem();
            if (selectedItem == null || selectedItem.getValue() == null) {
                showError("错误", "请先选择一个目录");
                return;
            }

            File targetDir = selectedItem.getValue();
            if (!targetDir.isDirectory()) {
                showError("错误", "选择的不是有效目录");
                return;
            }

            // 生成一个唯一的文件名
            String fileName = "clipboard_image_" + System.currentTimeMillis() + ".png";
            File targetFile = new File(targetDir, fileName);

            try {
                // 使用纯JavaFX方式保存图片
                saveImageToFile(image, targetFile);

                // 刷新当前目录
                loadImagesFromDirectory(targetDir);
                showMessage("成功粘贴图片");
            } catch (IOException ex) {
                showError("粘贴失败", "无法保存图片: " + ex.getMessage());
            }
        } else {
            showMessage("剪贴板中没有图片");
        }
    }

    // 使用纯JavaFX方式保存图片到文件
    private void saveImageToFile(javafx.scene.image.Image image, File file) throws IOException {
        // 创建一个可写的图像
        javafx.scene.image.WritableImage wImage;
        if (image instanceof javafx.scene.image.WritableImage) {
            wImage = (javafx.scene.image.WritableImage) image;
        } else {
            wImage = new javafx.scene.image.WritableImage(
                (int)image.getWidth(),
                (int)image.getHeight()
            );
            javafx.scene.image.PixelWriter pixelWriter = wImage.getPixelWriter();
            javafx.scene.image.PixelReader pixelReader = image.getPixelReader();

            for (int y = 0; y < image.getHeight(); y++) {
                for (int x = 0; x < image.getWidth(); x++) {
                    pixelWriter.setArgb(x, y, pixelReader.getArgb(x, y));
                }
            }
        }

        // 将图像数据转换为PNG格式并写入文件
        int width = (int) wImage.getWidth();
        int height = (int) wImage.getHeight();

        // 创建BufferedImage
        BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);

        // 从JavaFX图像复制像素数据到BufferedImage
        javafx.scene.image.PixelReader pixelReader = wImage.getPixelReader();
        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                bufferedImage.setRGB(x, y, pixelReader.getArgb(x, y));
            }
        }

        // 保存为PNG文件
        ImageIO.write(bufferedImage, "png", file);
    }

    // 生成新文件名（避免重名）
    private String generateNewFileName(File directory, String originalName) {
        String baseName = originalName;
        String extension = "";

        // 分离文件名和扩展名
        int dotIndex = originalName.lastIndexOf('.');
        if (dotIndex > 0) {
            baseName = originalName.substring(0, dotIndex);
            extension = originalName.substring(dotIndex);
        }

        int counter = 1;
        String newName;
        do {
            newName = baseName + "(" + counter++ + ")" + extension;
        } while (new File(directory, newName).exists());

        return newName;
    }

    private void showMessage(String message) {
        Alert alert = new Alert(Alert.AlertType.INFORMATION);
        alert.setTitle("提示");
        alert.setHeaderText(null);
        alert.setContentText(message);
        alert.showAndWait();
    }
}
